home *** CD-ROM | disk | FTP | other *** search
/ Libris Britannia 4 / science library(b).zip / science library(b) / COMMUNIC / 1572B.ZIP / KMT_IBM5.ZIP / MSSSCP.ASM next >
Assembly Source File  |  1989-07-11  |  97KB  |  1,874 lines

  1.         NAME    mssscp
  2. ; File MSSSCP.ASM
  3. ; Edit History
  4. ; Last edit 21 Nov 1988
  5. ; 21 Nov 1988 Version 2.32
  6. ; 20 Nov 1988 Correct timeout calculations to enforce 12 hour rule.
  7. ; 14 Nov 1988 Let SET INPUT ECHO OFF stop OUTPUT cmd from reading seria port.
  8. ; 10 Nov 1988 Omit "?timeout" message while in Take file or Macro.
  9. ; 16 Sept Let TRANSMIT command utilize SET EOF state for Control-Z. Tnx
  10. ;  to Terry Kennedy.
  11. ; 25 August Fix label match test when CR seen from file.
  12. ; 14 August Correct uninitialized DI register in bufclear. Tnx to Hirofumi
  13. ;  Fujii. Allow Transmit command prompt to use first ascii char if not a
  14. ;  number. Tnx to Bert Tyler.
  15. ; 6 August Tweak label matching code again.
  16. ; 28 July 1988 use full label lengths when doing label search, add command
  17. ;  IF EQUAL word word command. [jrd]
  18. ; 1 July 1988 Version 2.31
  19. ; 12 June 1988 Add error recovery if serial port does not initialize.
  20. ; 22 May 1988 Add more IF commands.
  21. ; 15 May 1988 Add commands GOTO, IF, REINPUT, and :label. [jrd]
  22. ; 20 March 1988 Put global script variables in structure script. [jrd]
  23. ; 8 March 1988 Add form of hh:[mm:[ss]] to input/pause/wait time intervals.
  24. ;  This form means timeout at the specified 24 hour clock time. [jrd]
  25. ; 27 Feb 1988 Add capability of stdin being a file.
  26. ; Introduce command   WAIT [sec] signal (signal is \cd or \dsr)
  27. ;  to wait on modem status. No signal means just wait, like pause. [jrd]
  28. ; 27 Jan 1988 Remove serrst call, done now in mssker idle loop. [jrd]
  29. ; 6 Jan 1988 Fix pointer for out @con calls. [jrd]
  30. ; 1 Jan 1988 version 2.30
  31. ; 26 Dec 1987 Use no-echo reading of console for OUTPUT @CON, speedup
  32. ;  reading of host response for OUTPUT command. [jrd]
  33. ; 4 Dec 1987 Update global byte errlev when a Script command Fails
  34. ;  (timeout or output failure or manual interruption). [jrd]
  35. ; 9 Oct 1987 Allow curly braced strings, trim trailing whitespace too. [jrd]
  36. ; 4 Oct 1987 Apply Set Display 7/8 bit mask to bytes rcv'd from serial port
  37. ;  after Set Translation Input filter. Log 8-bit chars in Debug mode. [jrd]
  38. ; 26 Sept 1987 Add check for Control-C interrupt to chkkbd and ECHO,
  39. ;  make Control-C in TRANSMIT command use squit exit. [jrd]
  40. ; 18 Aug 1987 Change ESC to escape for MASM 4.5+ [jrd]
  41. ; 11 Aug 1987 Add Set Send Pause plus 3 millisec wait before doing OUTPUT.[jrd]
  42. ; 31 July 1987 Open port reading to null chars et al. Correct timeofday
  43. ;  routine, from Jack Bryans. [jrd]
  44. ; 22 July 1987 Rewrite time of day material for no ambiguities. [jrd]
  45. ; 15 July 1987 Terminate strings read as @filespec on first carriage return.
  46. ;  Change number parsing to use decimal as default and \bddd for other bases.
  47. ; 24 May 1987 Add error recovery for outchr calls. [jrd]
  48. ; 10 May 1987 Add translation of input characters, rxtable. [jrd]
  49. ; 4 April 1987 Clear Echo's old text line, from Eberhard Lisse. [jrd]
  50. ; 18 March 1987 Add requests for command confirmation. [jrd]
  51. ; 2 March 1987 Remove test of Set Input Echo from OUTPUT command. [jrd]
  52. ; 27 Oct 1986 preserve data char in al around call to outchr in Output [jrd]
  53. ; 19 Oct 1986 Add "\b" and "\B" to Output procedure as send-a-Break command
  54. ;  to serial port comms line. [jrd]
  55. ; 1 Oct 1986 Version 2.29a
  56. ; 1 Oct 1986 Add 7/8 bit display mask to displayed text. [jrd]
  57. ; 12 Sept 1986 Add changes from Frank da Cruz: one second default timeout,
  58. ;  echo chars if Local Echo is On, Input command without a pattern should
  59. ;  behave like a Pause command.
  60. ;
  61. ; MS Kermit Script routines, DEC-20 style.
  62. ; Extensively rewritten for MS Kermit 2.29a by Joe R. Doupnik 5 July 86
  63. ;;
  64. ;    Created June, 1986 a.d.    By James Sturdevant
  65. ;                                         A. C. Nielsen Co. Mpls.
  66. ;                                         8401 Wayzata Blvd.
  67. ;                                         Minneapolis, Mn. 55426
  68. ;                                         (612)546-0600
  69. ;;;;;;;;
  70. ; Kermit command level usages and this file's entry points:
  71. ; Clear - clears serial port buffers. Procedure scclr.
  72. ; Echo text - displays text on local screen. Proc scecho.
  73. ; Pause [time] - waits indicated number of seconds (default is Input
  74. ;       Default-timeout, 1 second typically). Proc scpau.
  75. ; IF condtion command - tests condition (SUCCESS or FAILURE just now) and
  76. ;       if the condition is met executes the main-line Kermit command.
  77. ; GOTO label - rewinds Take file or Macro, locates the :label, transfers
  78. ;       parsing control to the next line.
  79. ; Input [time] text - waits up to time seconds while scanning serial port
  80. ;       input for a match with text. Default value for time is Input
  81. ;       Default-timeout, 1 second typically). Spaces or tabs are separators
  82. ;       between the time and text fields. Proc scinp.
  83. ;       A carriage return typed by the local user simulates a match.
  84. ; Reinput [time] text - like INPUT but non-destructively rereads the 128 byte
  85. ;       script buffer. Buffer can be added to, until full, if necessary.
  86. ; Output text - sends the text to the serial output port. Proc scout.
  87. ; Transmit text [prompt] - raw file transfer to host. Proceeds from source
  88. ;       line to source line upon receipt of prompt from host or carriage
  89. ;       return from us. Default prompt is linefeed. A null prompt (\0)
  90. ;       causes the file to be sent with no pausing or handshaking. Note
  91. ;       that linefeeds are stripped from outgoing material. Proc scxmit.
  92. ; In the above commands "text" may be replaced by "@filespec" to cause the
  93. ;       one line of that file to be used instead. @CON obtains one line of
  94. ;       text from the keyboard. Such "indirect command files" may be nested
  95. ;       to a depth of 100. Control codes are written as decimal numbers
  96. ;       in the form "\ddd" where d is a digit between 0 and 9. Carriage
  97. ;       return is \13, linefeed is \10, bell is \7; the special code \255
  98. ;       is used to match (Input) either cr or lf or both.
  99. ; These commands can be given individually by hand or automatically
  100. ;       in a Kermit Take file; Take files may be nested.
  101. ;;;;;;;;
  102. ; These routines expect to be invoked by the Kermit command dispatcher
  103. ; and can have their default operations controlled by the Kermit Set Input
  104. ; command (implemented in file mssset.asm). They parse their own cmd lines.
  105. ; Set Input accepts arguments of
  106. ;   Case Ignore or Observe  (default is ignore case when matching strings)
  107. ;   Default-timeout seconds (default is 5 seconds)
  108. ;   Echo On or Off      controls echoing of Input cmd text (default is Off)
  109. ;   Timeout-action Quit or Proceed (default is Proceed)
  110. ; These conditions are passed via global variables script.incasv, .indfto,
  111. ;   .inecho, .inactv, respectively, stored here in structure script.
  112. ;;;;;;;;;
  113.  
  114.         include mssdef.h
  115.         public  script, scout, scinp, scpau, scecho, scclr, scxmit, scwait
  116.         public  goto, screinp, ifcmd, setalrm, inptim, chktmo, alrhms
  117.  
  118. linelen         equ     134             ; length of working buffer line
  119. prtbuflen       equ     128             ; serial port local buffer length
  120. maxtry          equ     5               ; maximum number of output retries
  121. stat_unk        equ     0               ; status return codes.
  122. stat_ok         equ     1               ; have a port character
  123. stat_cc         equ     2               ; control-C typed
  124. stat_tmo        equ     4               ; timeout
  125. stat_cr         equ     8               ; carriage return typed
  126.  
  127. ifsuc           equ     0               ; indicators for IF conditions
  128. iffail          equ     1
  129. ifext           equ     2
  130. iferr           equ     3
  131. ifnot           equ     4
  132. ifctr           equ     5
  133. ifmdf           equ     6
  134. ifalarm         equ     7
  135. ifequal         equ     8
  136.  
  137. datas   segment public 'datas'
  138.         extrn   taklev:byte, takadr:word, portval:word, flags:byte
  139.         extrn   rxtable:byte, spause:byte, errlev:byte, fsta:word
  140.         extrn   kstatus:word, mcctab:byte, comand:byte, ttyact:byte
  141.  
  142.                                         ; global (public) variables
  143. script  scptinfo <>                     ; global structure, containing:
  144. ;;inactv        db      0               ; input action value (default proceed)
  145. ;;incasv        db      0dfh            ; input case  (default ignore)
  146. ;;indfto        dw      1               ; input and pause timeout (def 1 sec)
  147. ;;inecho        db      1               ; echo Input cmd text (0 = no)
  148.                                         ; local variables
  149. line    db      linelen+1 dup (?)       ; line of output or input + terminator
  150. prtbuf  db      prtbuflen dup (?)       ; serial port storage buffer
  151. bufcnt  dw      0                       ; serial port buf byte cnt, must be 0
  152. bufrdptr dw     prtbuf                  ; serial port buf read ptr
  153. bufwtptr dw     prtbuf                  ; serial port buf write ptr
  154. bufpkptr dw     prtbuf                  ; peek-read pointer
  155. bufpkcnt dw     0                       ; peek-read byte count remaining
  156. reinflg db      0                       ; 0 = INPUT, else REINPUT command
  157. inplen  dw      0                       ; length of input match string
  158. notflag db      0                       ; IF NOT flag
  159. slablen dw      0                       ; label length, for GOTO
  160. temptr  dw      ?                       ; temporary pointer
  161. temptr2 dw      ?                       ; ditto, points to end of INPUT string
  162. tempd   dw      ?                       ; temp
  163. tempa   db      ?                       ; another temp
  164. retry   db      0                       ; number of output retries
  165. status  dw      ?                       ; general status word
  166. fhandle dw      ?                       ; file handle storage place
  167. parmsk  db      7fh                     ; 7/8 bit parity mask
  168. lecho   db      ?                       ; local echo of output (0 = no)
  169. timout  dw      ?                       ; work area (seconds before timeout)
  170. timhms  db      4 dup (?)               ; hhmmss.s time of day buffer
  171. alrhms  db      4 dup (?)               ; hhmmss.s time of day alarm buffer
  172. eolchr  db      LF                      ; end of line character
  173.  
  174. crlf    db      cr,lf,'$'
  175. xfrfnf  db      cr,lf,'?Transmit file not found$'
  176. xfrrer  db      cr,lf,'?error reading Transmit file$'
  177. xfrcan  db      cr,lf,'?Transmission canceled$'
  178. indmis  db      '?Indirect file not found',cr,lf,'$'
  179. inderr  db      '?error reading indirect file',cr,lf,'$'
  180. laberr  db      cr,lf,'?Label ":$'
  181. laberr2 db      '" was not found.',cr,lf,'$'
  182. tmomsg  db      cr,lf,'?Timeout',cr,'$'
  183. outhlp  db      'line of text to be sent to remote host$'
  184. inphlp  db      'time-limit and line of text expected from remote host'
  185.         db      cr,lf,' Time is number of seconds or until a specific'
  186.         db      ' hh:mm:ss (24 hour clock)$'
  187. echhlp  db      'line of text to be Echoed to screen$'
  188. ptshlp  db      'amount of time to pause'
  189.         db      cr,lf,' Time is number of seconds or until a specific'
  190.         db      ' hh:mm:ss (24 hour clock)$'
  191. wthlp   db      'time-limit and modem status signals \CD, \CTS, and \DSR'
  192.         db      cr,lf,' Time is number of seconds or until a specific'
  193.         db      ' hh:mm:ss (24 hour clock)$'
  194. xmthlp  db      ' Name of file to be Transmitted$'
  195. pmthlp  db      cr,lf
  196.         db     ' Prompt character expected as an ACK from host (\0 for none)$'
  197. ifdfhlp db      cr,lf,' Name of macro or variable  then a command$'
  198. alrmhlp db      cr,lf,' Seconds from now or time of day (HH:MM:SS) for alarm,'
  199.         db      ' < 12H from present$'
  200. ifnhlp  db      cr,lf,' Number which errorlevel should match or exceed$'
  201. ifnmsg  db      cr,lf,'?Number expected, ignoring "$'
  202. ifnmsg2 db      '"$'
  203. discard db      ' Kermit command'
  204.         db      cr,lf,' "IF" condition is false, command will be ignored.$'
  205. ifehlp1 db      cr,lf,'?pair of words or variables to be compared$'
  206. ifehlp2 db      cr,lf,'?second word or variable to be compared$'
  207.  
  208. iftable db      9                       ; IF command dispatch table
  209.         mkeyw   'Not',ifnot
  210.         mkeyw   'Alarm',ifalarm
  211.         mkeyw   'Count',ifctr
  212.         mkeyw   'Defined',ifmdf
  213.         mkeyw   'Errorlevel',iferr
  214.         mkeyw   'Equal',ifequal
  215.         mkeyw   'Exist',ifext
  216.         mkeyw   'Failure',iffail
  217.         mkeyw   'Success',ifsuc
  218. datas   ends
  219.  
  220. code    segment public 'code'
  221.  
  222.         extrn   comnd:near, clrbuf:near, prtchr:near, outchr:near, sendbr:near
  223.         extrn   cptchr:near, serini:near, serrst:near, pcwait:near, katoi:near
  224.         extrn   cnvstr:near, getmodem:near, isdev:near, isfile:near
  225.         extrn   takrd:near, takclos:near, tolowr:near, prtasz:near,strlen:near
  226.  
  227.         assume  cs:code, ds:datas, es:nothing
  228.  
  229. ; Clear input buffer(s) of serial port
  230. ; Clear command
  231. ;
  232. SCCLR   PROC    NEAR
  233.         mov     kstatus,0               ; global status
  234.         mov     ah,cmcfm                ; get a confirm
  235.         call    comnd
  236.          jmp    r                       ; no confirm
  237.          nop
  238.         call    bufclear                ; clear our serial port circular buf
  239.         call    clrbuf                  ; clear system serial port buffer too
  240.         jmp     rskp                    ; return success
  241. SCCLR   ENDP
  242.  
  243. ;
  244. ; Echo a line of text to our screen
  245. ; Echo text
  246. ;
  247. SCECHO  PROC    NEAR
  248.         mov     ah,cmtxt                ; get a whole line of asciiz text
  249.         mov     bx,offset line          ; where to store in
  250.         mov     word ptr [bx],0         ; clear line
  251.         mov     dx,offset echhlp        ; help
  252.         call    comnd
  253.          jmp    rskp                    ; ignore parse error if no text
  254.          nop
  255.         mov     si,offset line          ; start of line
  256.         mov     di,si                   ; convert to the same place
  257.         mov     ah,script.incasv        ; save current case state
  258.         push    ax
  259.         mov     script.incasv,0ffh      ; say no case conversion
  260.         call    cnvlin                  ; convert \numbers to binary
  261.         pop     ax
  262.         mov     script.incasv,ah        ; recover case state
  263.         jc      echo3                   ; carry set means error
  264.         mov     al,lf                   ; start with a linefeed
  265.         call    scdisp                  ; show it
  266.         jcxz    echo2                   ; z = nothing to show
  267. echo1:  push    cx                      ; save loop counter
  268.         cld
  269.         lodsb                           ; get a source char into al
  270.         push    si
  271.         call    scdisp                  ; display the char
  272.         pop     si
  273.         pop     cx
  274.         loop    echo1                   ; get another
  275. echo2:  jmp     rskp                    ; return success
  276. echo3:  ret                             ; error
  277. SCECHO  ENDP
  278.  
  279. ; Extract label from command line. Store in LINE, length in slablen.
  280. ; Jump to line in Take or Macro following that label.
  281. GOTO    PROC    NEAR
  282.         mov     kstatus,0               ; global status
  283.         mov     ah,cmfile               ; get a word
  284.         mov     dx,offset line          ; buffer to hold label
  285.         mov     bx,0                    ; no help (non-interactive command)
  286.         mov     slablen,bx              ; clear label holding buffer
  287.         mov     comand.cmkeep,1         ; keep Take/macro open after EOF
  288.         call    comnd
  289.          jmp    r
  290.          nop
  291.         mov     al,ah                   ; byte count
  292.         mov     ah,0
  293.         mov     slablen,ax              ; save count here
  294.         mov     comand.cmkeep,1
  295.         mov     ah,cmcfm
  296.         call    comnd
  297.          jmp    r
  298.          nop
  299.         cmp     taklev,0                ; in a Take file or Macro?
  300.         jne     GETTO                   ; ne = yes, find the label
  301.         jmp     rskp                    ; ignore interactive command
  302.  
  303. ; Find line starting just after ":label". Label is in variable LINE
  304. ; (length in slablen). Readjust Take read pointer to start of that line.
  305. ; Performs file search from beginning of file.
  306. ; Exit carry clear if success, carry set otherwise. Local worker routine.
  307. getto   proc    near
  308.         push    bx                      ; global save of bx
  309.         mov     bx,takadr
  310.         cmp     [bx].taktyp,0ffh        ; get type of take (a Macro?)
  311.         je      gett2                   ; e = yes, a macro
  312.                                         ; scan from start of Take file
  313.         mov     eolchr,LF               ; file lines end on LF
  314.         mov     bx,[bx].takhnd          ; rewind the file
  315.         mov     cx,0
  316.         mov     dx,0
  317.         mov     al,0                    ; zero displacement from start of file
  318.         mov     ah,lseek
  319.         int     dos
  320.         jnc     gett1
  321.         jmp     gett20                  ; c = failure
  322. gett1:  call    takrd                   ; get a buffer of data
  323.         mov     bx,takadr               ; restore bx to working value
  324.         jmp     short gett4
  325.                                         ; Take a Macro
  326. gett2:  mov     eolchr,CR               ; Macro lines end on CR
  327.         mov     ax,[bx].takptr          ; offset of next char to be read
  328.         sub     ax,[bx].takbuf          ; offset of start of buffer
  329.         dec     ax                      ; omit count byte at start of buffer
  330.         add     [bx].takcnt,ax          ; original length of text in buffer
  331.         mov     ax,[bx].takbuf
  332.         inc     ax                      ; omit count byte at start of buffer
  333.         mov     [bx].takptr,ax          ; set read pointer to beginning
  334.  
  335. gett4:  call    getch                   ; get a character
  336.         jc      gett14                  ; c = end of file, no char
  337.         cmp     al,':'                  ; start of label?
  338.         je      gett8                   ; e = yes
  339. gett6:  cmp     al,eolchr               ; end of line?
  340.         je      gett4                   ; e = yes, seek colon for label
  341.         call    getch                   ; get a character
  342.         jc      gett14                  ; c = end of file, no char
  343.         jmp     short gett6             ; read until end of line
  344. gett8:  mov     si,offset line          ; label to search for
  345.         mov     cx,slablen              ; its length
  346.         jcxz    gett12                  ; no chars to match
  347.         cmp     byte ptr[si],':'        ; user label starts with colon
  348.         jne     gett10                  ; ne = no
  349.         inc     si                      ; skip user's colon
  350.         dec     cx
  351.         jcxz    gett12                  ; no chars to match
  352. gett10: call    getch                   ; read file char into al
  353.         jc      gett14                  ; c = end of file
  354.         mov     ah,al
  355.         cld
  356.         lodsb
  357.         call    tolowr                  ; convert al and ah to lower case
  358.         cmp     al,ah                   ; match?
  359.         jne     gett6                   ; ne = no, goto end of line
  360.         loop    gett10                  ; continue matching
  361.                                         ; match obtained
  362.         call    getch                   ; read next file character
  363.         jc      gett13                  ; c = end of file, no char
  364.         cmp     al,' '                  ; separator?
  365.         je      gett12                  ; e = yes, unique label found
  366.         cmp     al,eolchr               ; or end of line?
  367.         je      gett13                  ; e = yes
  368.         cmp     al,CR                   ; macro eol, also file start eol pair
  369.         je      gett12                  ; e = found match
  370.         jmp     gett6                   ; longer label than target
  371.  
  372. gett12: call    getch                   ; read past end of line
  373.         jc      gett13                  ; c = end of file, no char
  374.         cmp     al,eolchr               ; end of line character?
  375.         jne     gett12                  ; ne = no, keep reading
  376. gett13: pop     bx
  377.         clc                             ; return carry clear
  378.         jmp     rskp                    ; Take pointers are ready to read line
  379.  
  380. gett14: mov     ah,prstr                ; say label not found
  381.         mov     dx,offset laberr        ; first part of error message
  382.         int     dos
  383.         mov     dx,offset line
  384.         cmp     line,':'                ; label starts with ":"?
  385.         jne     gett15                  ; ne = no
  386.         inc     dx                      ; yes, skip it
  387. gett15: call    prtasz                  ; print asciiz string
  388.         mov     ah,prstr
  389.         mov     dx,offset laberr2       ; trailer of error message
  390.         int     dos
  391. gett20: pop     bx
  392.         mov     kstatus,1               ; command status, failure
  393.         stc                             ; set carry for failure
  394.         ret
  395. getto   endp
  396. GOTO    ENDP
  397.  
  398. ; Read char from Take buffer. Returns carry clear and char in al, or if end
  399. ; of file returns carry set. Enter with bx holding takadr. Local worker.
  400. getch   proc    near
  401.         cmp     [bx].takcnt,0           ; buffer empty?
  402.         jg      getch2                  ; g = no
  403.         cmp     [bx].taktyp,0ffh        ; macro?
  404.         je      getch1                  ; e = yes, that's the end
  405.         call    takrd                   ; read another buffer
  406.         cmp     [bx].takcnt,0           ; end of file?
  407.         jne     getch2                  ; ne = no
  408. getch1: stc                             ; e = yes, exit error
  409.         ret
  410. getch2: push    si
  411.         mov     si,[bx].takptr          ; read a char from Take buffer
  412.         cld
  413.         lodsb
  414.         mov     [bx].takptr,si          ; move buffer pointer
  415.         pop     si
  416.         dec     [bx].takcnt             ; decrease number of bytes remaining
  417.         clc                             ; return carry clear
  418.         ret
  419. getch   endp
  420.  
  421. ; IF [NOT] {ALARM | COUNT | FAILURE | SUCCESS | ERRORLEVEL \number
  422. ;                 | EQUAL string string | EXIST filespec} command
  423.  
  424. IFCMD   PROC    NEAR
  425.         mov     notflag,0               ; assume NOT keyword is absent
  426. ifcmd1: mov     ah,cmkey                ; parse keyword
  427.         mov     dx,offset iftable       ; table of keywords
  428.         mov     bx,0                    ; help is the table
  429.         call    comnd
  430.          jmp    r
  431.          nop
  432.         cmp     bx,ifnot                ; NOT keyword?
  433.         jne     ifcmd2                  ; ne = no
  434.         xor     notflag,1               ; toggle not flag
  435.         jmp     short ifcmd1            ; and get next keyword
  436.  
  437. ifcmd2: cmp     bx,ifsuc                ; IF SUCCESS?
  438.         jne     ifcmd4                  ; ne = no
  439.         cmp     kstatus,0               ; do we have success?
  440.         jne     ifcmdf                  ; ne = no, no jump
  441.         jmp     ifcmdp                  ; yes
  442.  
  443. ifcmd4: cmp     bx,iferr                ; IF ERRORLEVEL?
  444.         jne     ifcmd5                  ; ne = no
  445.         jmp     ifnum                   ; parse number to binary in line
  446.  
  447. ifcmd5: cmp     bx,ifext                ; IF EXIST filespec?
  448.         jne     ifcmd6                  ; ne = no
  449.         mov     ah,cmfile               ; read a filespec
  450.         mov     dx,offset line          ; buffer for filespec
  451.         mov     bx,0
  452.         call    comnd
  453.          jmp    r
  454.          nop
  455.         mov     ax,offset line          ; isfile wants pointer in ds:ax
  456.         call    isfile                  ; see if file exists
  457.         jc      ifcmdf                  ; c = no
  458.         jmp     short ifcmdp            ; yes, do following command
  459.  
  460. ifcmd6: cmp     bx,iffail               ; IF FAIL?
  461.         jne     ifcmd7
  462.         test    kstatus,not (0)         ; check all bits
  463.         jz      ifcmdf                  ; z = not that condition, no jump
  464.         jmp     short ifcmdp
  465.  
  466. ifcmd7: cmp     bx,ifctr                ; IF COUNT?
  467.         jne     ifcmd8                  ; ne = no
  468.         cmp     taklev,0                ; in a Take file?
  469.         je      ifcmdf                  ; e = no, fail
  470.         push    bx
  471.         mov     bx,takadr               ; current Take structure
  472.         cmp     [bx].takctr,0           ; exhausted count?
  473.         je      ifcmd7a                 ; e = yes, dec no more ye counter
  474.         dec     [bx].takctr             ; dec COUNT if non-zero
  475.         cmp     [bx].takctr,0           ; exhausted now?
  476.         je      ifcmd7a                 ; e = yes
  477.         pop     bx
  478.         jmp     short ifcmdp            ; COUNT > 0 at entry, execute command
  479. ifcmd7a:pop     bx
  480.         jmp     short ifcmdf            ; do not execute command
  481.  
  482. ifcmd8: cmp     bx,ifmdf                ; IF DEF?
  483.         jne     ifcmd9                  ; ne = no
  484.         jmp     ifmdef                  ; do further parsing below
  485.  
  486. ifcmd9: cmp     bx,ifalarm              ; IF ALARM?
  487.         jne     ifcmd10                 ; ne = no
  488.         jmp     ifalrm                  ; do further parsing below
  489.  
  490. ifcmd10:cmp     bx,ifequal              ; IF EQUAL?
  491.         jne     ifcmdf                  ; ne = no
  492.         jmp     ifequ                   ; do further parsing below
  493.                                         ; Jump points for worker routines
  494.                                         ; failure
  495. ifcmdf: cmp     notflag,0               ; need to apply not condition?
  496.         jne     ifcmdp2                 ; ne = yes, take other exit
  497. ifcmdf2:mov     ah,cmtxt                ; fail, read and discard rest of line
  498.         mov     bx,offset line
  499.         mov     dx,offset discard       ; say not doing anything
  500.         call    comnd
  501.          nop
  502.          nop
  503.          nop
  504.         jmp     rskp
  505.                                         ; success (pass)
  506. ifcmdp: cmp     notflag,0               ; need to apply not condition?
  507.         jne     ifcmdf2                 ; ne = yes, take other exit
  508. ifcmdp2:jmp     rskp                    ; do command
  509. IFCMD   ENDP
  510.  
  511. ; Compare errlev against user number. Jump successfully if errlev >= number.
  512. ; Worker for IF [NOT] ERRORLEVEL number <command>
  513. ifnum   proc    near
  514.         mov     ah,cmfile               ; get following number
  515.         mov     dx,offset line+1
  516.         mov     line,'\'                ; in case user forgets backslash
  517.         mov     word ptr line+1,0       ; clear buffer
  518.         mov     bx,offset ifnhlp        ; help
  519.         call    comnd
  520.          jmp    r
  521.          nop
  522.         mov     si,offset line          ; put text in compare buffer
  523.         cmp     line+1,'\'              ; did user include backslash?
  524.         jne     ifnum2                  ; ne = no
  525.         inc     si                      ; yes, skip our helpful backslash
  526. ifnum2: call    katoi                   ; convert number to binary in ax
  527.         jc      ifnum4                  ; c = failed to convert a number
  528.         cmp     errlev,al               ; at or above this level?
  529.         jae     ifnum3                  ; ae = yes, succeed
  530.         jmp     ifcmdf                  ; else fail
  531. ifnum3: jmp     ifcmdp                  ; jump to main command Success exit
  532.  
  533. ifnum4: mov     dx,offset line+1        ; pointer to bad word
  534.         mov     tempd,dx                ; remember starting place for text
  535.         call    strlen                  ; get its length
  536.         add     dx,cx                   ; skip over current word
  537.         mov     bx,dx
  538.         mov     byte ptr [bx],' '       ; space, chopped by parser
  539.         inc     bx                      ; new text goes here
  540.         mov     dx,0                    ; help
  541.         mov     ah,cmtxt                ; read rest of line
  542.         call    comnd
  543.          jmp    r
  544.          nop
  545.         cmp     ah,0                    ; returned byte count
  546.         ja      ifnum5                  ; a = got some
  547.         mov     byte ptr[bx-1],0        ; remove space separator from above
  548. ifnum5: mov     ah,prstr
  549.         mov     dx,offset ifnmsg        ; error message header
  550.         int     dos
  551.         mov     dx,offset line+1        ; start of user text
  552.         call    prtasz                  ; display asciiz string
  553.         mov     ah,prstr
  554.         mov     dx,offset ifnmsg2       ; trailer of message
  555.         int     dos
  556.         jmp     ifcmdf                  ; jump to main command Failure exit
  557. ifnum   endp
  558.  
  559. ; Process IF [NOT] DEF <macro name> <command>
  560. ifmdef  proc    near
  561.         mov     dx,offset line+1        ; point to work buffer
  562.         mov     bx,offset ifdfhlp       ; help
  563.         mov     ah,cmfile               ; get macro name
  564.         mov     comand.cmper,1          ; do not react to \%x
  565.         call    comnd
  566.          jmp    r
  567.          nop
  568.         mov     line,ah                 ; store length in buffer
  569. ifmde2: mov     bx,offset mcctab+1      ; table of macro keywords
  570.         mov     tempd,0                 ; tempd = current keyword
  571.         cmp     byte ptr [bx-1],0       ; any macros defined?
  572.         je      ifmde9                  ; e = no, failure, exit now
  573.                                         ; match table keyword and user word
  574. ifmde3: mov     si,offset line          ; pointer to user's cnt+name
  575.         mov     cl,[si]                 ; length of user's macro name
  576.         xor     ch,ch
  577.         inc     si                      ; point to macro name
  578.         cmp     cl,[bx]                 ; compare length vs table keyword
  579.         jne     ifmde7                  ; ne = not equal lengths, try another
  580.         push    si                      ; lengths match, how about spelling?
  581.         push    bx
  582.         inc     bx                      ; point at start of keyword
  583. ifmde4: mov     ah,[bx]                 ; keyword char
  584.         mov     al,[si]                 ; new text char
  585.         cmp     al,'a'                  ; map lower case to upper
  586.         jb      ifmde5
  587.         cmp     al,'z'
  588.         ja      ifmde5
  589.         sub     al,'a'-'A'
  590. ifmde5: cmp     al,ah                   ; test characters
  591.         jne     ifmde6                  ; ne = no match
  592.         inc     si                      ; move to next char
  593.         inc     bx
  594.         loop    ifmde4                  ; loop through entire length
  595. ifmde6: pop     bx
  596.         pop     si
  597.         jcxz    ifmde10                 ; z: cx = 0, found the name
  598.                                         ; select next keyword
  599. ifmde7: inc     tempd                   ; number of keyword to test next
  600.         mov     cx,tempd
  601.         cmp     cl,mcctab               ; all done? Recall, tempd starts at 0
  602.         jae     ifmde9                  ; ae = yes, no match
  603. ifmde8: mov     al,[bx]                 ; cnt (keyword length from macro)
  604.         xor     ah,ah
  605.         add     ax,4                    ; skip over '$' and two byte value
  606.         add     bx,ax                   ; bx = start of next keyword slot
  607.         jmp     short ifmde3            ; do another comparison
  608. ifmde9: jmp     ifcmdf                  ; jump to main command Failure exit
  609. ifmde10:jmp     ifcmdp                  ; jump to main command Success exit
  610. ifmdef  endp
  611.  
  612. ; IF [not] ALARM hh:mm:ss command
  613. ifalrm  proc    near
  614.         call    chkkbd                  ; check keyboard for override
  615.         test    status,stat_cc          ; Control-C?
  616.         jz      ifalr1                  ; z = no
  617.         ret                             ; yes, return failure now
  618. ifalr1: push    word ptr timhms
  619.         push    word ptr timhms+2       ; save working timeouts
  620.         mov     ax,word ptr alrhms
  621.         mov     word ptr timhms,ax
  622.         mov     ax,word ptr alrhms+2
  623.         mov     word ptr timhms+2,ax    ; set alarm value
  624.         call    chktmo                  ; check for timeout
  625.         pop     word ptr timhms+2       ; restore working timeouts
  626.         pop     word ptr timhms
  627.         test    status,stat_tmo         ; tod past user time (alarm sounded)?
  628.         jnz     ifalr4                  ; nz = yes, succeed
  629.                                         ; failure (not at alarm time yet)
  630. ifalr2: cmp     notflag,0               ; need to apply not condition?
  631.         jne     ifalr5                  ; ne = yes, take other exit
  632. ifalr3: mov     ah,cmtxt                ; fail, read and discard rest of line
  633.         mov     bx,offset line
  634.         mov     dx,0
  635.         call    comnd
  636.          jmp    r
  637.          nop
  638.         jmp     rskp
  639.                                         ; success (at or past alarm time)
  640. ifalr4: cmp     notflag,0               ; need to apply not condition?
  641.         jne     ifalr3                  ; ne = yes, take other exit
  642. ifalr5: jmp     rskp                    ; pass, do command
  643. ifalrm  endp
  644.  
  645. ; IF [NOT] EQUAL word word command
  646. ; Permits use of \number, {string}, @filespec
  647. ifequ   proc    near
  648.         mov     ah,cmfile               ; get a word
  649.         mov     dx,offset line          ; where to store
  650.         mov     line,0                  ; clear first entry
  651.         mov     bx,offset ifehlp1       ; help
  652.         call    comnd
  653.          jmp    rskp                    ; ignore parse error if no text
  654.          nop
  655.         mov     si,offset line          ; start of line
  656.         mov     di,si                   ; convert to the same place
  657.         call    cnvlin                  ; convert \numbers to binary
  658.         jc      ifequ9                  ; carry set means error
  659.         jcxz    ifequ9                  ; z = empty word
  660.         mov     tempa,0                 ; line length, so far
  661.         cld
  662. ifequ1: lodsb
  663.         cmp     al,' '                  ; space or control code?
  664.         jbe     ifequ2                  ; be = yes, end of word
  665.         inc     tempa                   ; count char in word
  666.         loop    ifequ1                  ; continue
  667. ifequ2: mov     byte ptr[si],0          ; plant terminator
  668.         inc     si                      ; skip null terminator
  669.         mov     temptr,si               ; place to start second part
  670.         mov     dx,si
  671.         mov     word ptr[si],0          ; clear second part
  672.         mov     ah,cmfile               ; get a word of text
  673.         mov     bx,offset ifehlp2       ; help
  674.         call    comnd
  675.          jmp    rskp                    ; ignore parse error if no text
  676.          nop
  677.         mov     si,temptr               ; start of second line
  678.         mov     di,si                   ; convert to the same place
  679.         call    cnvlin                  ; convert \numbers to binary
  680.         jc      ifequ9                  ; carry set means error
  681.         jcxz    ifequ9                  ; z = empty word
  682.         mov     si,temptr               ; point at second word
  683.         mov     dx,0                    ; word length so far
  684.         cld
  685. ifequ3: lodsb
  686.         cmp     al,' '                  ; space or control code?
  687.         jbe     ifequ4                  ; be = yes, end of word
  688.         inc     dx                      ; count char in word
  689.         loop    ifequ3                  ; continue
  690. ifequ4: mov     byte ptr[si],0          ; plant terminator
  691.         mov     cx,dx                   ; length of second word
  692.         cmp     tempa,dl                ; same lengths?
  693.         jne     ifequ9                  ; ne = no
  694.         jcxz    ifequ9                  ; both are null
  695.         push    es
  696.         push    ds
  697.         pop     es
  698.         mov     si,offset line          ; first word
  699.         mov     di,temptr               ; second word
  700.         cld
  701.         repe    cmpsb                   ; see if they are the same
  702.         pop     es
  703.         jne     ifequ9                  ; ne = not the same, fail
  704.         jmp     ifcmdp                  ; do IF cmd success
  705. ifequ9: jmp     ifcmdf                  ; do IF cmd failure
  706. ifequ   endp
  707.  
  708. ; SET ALARM <time, sec from now or HH:MM:SS>
  709. SETALRM PROC    NEAR
  710.         mov     dx,offset line          ; point to work buffer
  711.         mov     word ptr line,0
  712.         mov     word ptr line+2,0
  713.         mov     bx,offset alrmhlp       ; help
  714.         mov     ah,cmfile               ; get macro name
  715.         call    comnd
  716.          jmp    r
  717.          nop
  718.         mov     ah,cmcfm                ; get a confirm
  719.         call    comnd
  720.          jmp    r
  721.          nop
  722.         push    word ptr timhms
  723.         push    word ptr timhms+2       ; save working timeouts
  724.         mov     si,offset line          ; source pointer
  725.         call    inptim                  ; get the timeout time, sets si
  726.         mov     ax,word ptr timhms      ; save time in alarm area
  727.         mov     word ptr alrhms,ax
  728.         mov     ax,word ptr timhms+2
  729.         mov     word ptr alrhms+2,ax
  730.         pop     word ptr timhms+2       ; restore working timeouts
  731.         pop     word ptr timhms
  732.         jmp     rskp
  733. SETALRM ENDP
  734.  
  735. ; REINPUT <timeout> <match text>
  736. ; Reread material in serial port buffer, seeking a match with user's text
  737. ; pattern. If user's pattern is longer than material in buffer then read
  738. ; additional characters from the serial port. Use SCINP to do the main work.
  739.  
  740. SCREINP PROC    NEAR
  741.         mov     reinflg,1               ; say doing REINPUT, not INPUT
  742.         jmp     short input10
  743. SCREINP ENDP
  744.  
  745. ; Input from port command, match input with text pattern
  746. ; Input [timeout] text
  747. ;
  748. SCINP   PROC    NEAR
  749.         mov     reinflg,0               ; say doing INPUT, not REINPUT
  750.         jmp     short input10
  751.  
  752. input10:mov     kstatus,0
  753.         mov     ah,cmtxt                ; get a whole line of asciiz text
  754.         mov     bx,offset line          ; place to put text
  755.         mov     dx,offset inphlp        ; help message
  756.         call    comnd                   ; get the pattern text
  757.          jmp    r                       ; nothing, complain
  758.          nop
  759.         cmp     reinflg,0               ; Input command?
  760.         jne     input1                  ; ne = no, Reinput
  761.         cmp     taklev,0                ; are we in a Take file?
  762.         je      input0                  ; e = no, display linefeed
  763.         cmp     flags.takflg,0          ; are Take commands being echoed?
  764.         je      input1                  ; e = no, skip display
  765. input0: cmp     script.inecho,0         ; Input echo off?
  766.         je      input1                  ; e = yes
  767.         mov     al,lf                   ; next line
  768.         call    scdisp                  ; display the char
  769. input1: call    serini                  ; initialize the system's serial port
  770.         jc      input1a                 ; c = failure
  771.         mov     status,stat_unk         ; clear status flag
  772.         mov     si,offset line          ; source pointer
  773.         call    inptim                  ; get the timeout time, sets si
  774.         jnc     input1b                 ; nc = legal time value or none
  775. input1a:jmp     input5                  ; else fail on error
  776. input1b:mov     di,offset line          ; put text in compare buffer
  777.         call    cnvlin                  ; convert \numbers in buf line
  778.         mov     inplen,cx               ; cx = number of bytes in final string
  779.         mov     parmsk,0ffh             ; parity mask, assume 8 bit data
  780.         mov     di,portval
  781.         cmp     [di].parflg,parnon      ; parity is none?
  782.         je      input1c                 ; e = none
  783.         mov     parmsk,07fh             ; else strip parity (8th) bit
  784. input1c:mov     di,offset line
  785.         mov     temptr,di               ; pointer to pattern char
  786.         mov     temptr2,di              ; and we need pointer to end of string
  787.         add     temptr2,cx              ; offset of end of string
  788.                                         ; setup reinput read pointer & count
  789.         mov     ax,bufwtptr             ; where next new char goes
  790.         mov     bufpkptr,ax             ; set peek-read pointer at oldest char
  791.         mov     bufpkcnt,prtbuflen      ; always look back one full buffer
  792.                                         ; see if a pattern needs matching
  793.         cmp     inplen,0                ; empty pattern? (cnvlin sets cx=cnt)
  794.         jne     input4                  ; ne = not empty
  795.         cmp     reinflg,0               ; Input command?
  796.         je      input3                  ; e = yes, read and discard chars
  797.         jmp     input5                  ;  reinput, just exit timeout
  798.  
  799.                                         ; empty. read, display, and discard
  800. input3: call    chkkbd                  ; check keyboard
  801.         test    status,stat_cc          ; did user type control-c?
  802.         jnz     input5                  ; nz = yes, quit
  803.         test    status,stat_cr          ; did user type cr? [js]
  804.         jz      input3a                 ; z = no
  805.         jmp     inputx                  ; nz = yes, return success [js]
  806. input3a:call    chktmo                  ; check timeout
  807.         test    status,stat_tmo
  808.         jnz     input5                  ; nz = timed out, quit
  809.         call    bufread                 ; read from serial port buffer into al
  810.         jmp     input3                  ; loop until timeout, exit timeout
  811.  
  812.                                         ; start main read and compare loop
  813. input4: mov     di,temptr               ; pointer to current pattern char
  814.         cmp     di,temptr2              ; at end of pattern?
  815.         jae     inputx                  ; ae = yes, return success
  816.         call    chkkbd                  ; check keyboard
  817.         test    status,stat_cc          ; did user type control-c?
  818.         jnz     input5                  ; nz = yes, quit
  819.         test    status,stat_cr          ; did user type cr? [js]
  820.         jz      input4a                 ; z = no
  821.         jmp     inputx                  ; nz = yes, return success [js]
  822. input4a:call    chktmo                  ; check timeout
  823.         test    status,stat_tmo+stat_ok ; timeout or user override
  824.         jnz     input5                  ; nz = timed out, quit
  825.         cmp     reinflg,0               ; Input command?
  826.         jne     input4b                 ; ne = no, a reinput cmd
  827.         call    bufread                 ; read from serial port buffer into al
  828.         jc      input4                  ; c = nothing there, keep looking
  829.         jmp     short input4c           ; analyze character
  830. input4b:call    peekbuf                 ; reinput: peek-read from buffer
  831.         jc      input4                  ; c = failed to get a character
  832.                                         ; got a char from buffer/port
  833. input4c:cmp     al,'a'                  ; candidate for case conversion? [js]
  834.         jb      input4d                 ; b = no [js]
  835.         cmp     al,'z'                  ; in lower case set? [js]
  836.         ja      input4d                 ; a = no [js]
  837.         and     al,script.incasv        ; apply case conversion mask
  838. input4d:mov     di,temptr
  839.         mov     ah,byte ptr [di]        ; get current pattern char again
  840.         call    matchr                  ; al=rcvd, ah=pattern, do they match?
  841.         jc      inpm                    ; c = no match, try substring
  842.         inc     temptr                  ; matched, point to next pattern char
  843.         jmp     input4
  844. input5: or      errlev,2                ; set RECEIVE failure condition
  845.         or      fsta.xstatus,2          ; set status
  846.         cmp     reinflg,0               ; Input command?
  847.         jne     input6                  ; ne = no
  848.         jmp     squit                   ; exit failure: timeout or control-c
  849. input6: mov     kstatus,2               ; failure
  850.         jmp     squit1                  ; skip timeout message, if any
  851. inputx: jmp     rskp                    ; return success
  852. ; See if a trailing-subset of the matched chars + new port char can match
  853. ; the beginning part of the pattern. That is, if we were to simply "forget"
  854. ; the oldest of the matched chars and slide left the apparent port string
  855. ; then could we eventually find a match? Example: "Input 10 memema"
  856. ; gives the pattern of "memema"; suppose the received chars were "mememema".
  857. ; Forgetting one left-most rcv'd char at a time (two in this case) finally
  858. ; yields a match, from which we should continue to compare fresh port chars
  859. ; with successive pattern chars until either they match through all pattern
  860. ; chars or we encounter another break. If there is a later break, repeat this
  861. ; algorithm.
  862. ; Since we really have only the latest char from the port then pointers to
  863. ; the matched pattern chars are used to mimic the earlier received chars:
  864. ; they must have been identical to produce a match to date. The quick way
  865. ; to "forget" oldest received chars is to scan backward through the matched
  866. ; pattern chars looking for the current port char; if the first such find does
  867. ; not yield a matching substring then look back further.
  868.                                 ; no or partial match then break
  869.                                 ; di = temptr = pattern break char
  870.                                 ; al = port char causing break
  871.                                 ; di - offset line = # chars matched thus far
  872.                         ; avoid cpu-brand side effects with "repne scasb"
  873. inpm:   mov     tempa,al        ; save port char here
  874. inpm1:  mov     tempd,di        ; pattern break loc, where matching failed
  875.         mov     cx,di           ; char at di does not match current port char
  876.         sub     cx,offset line  ; compute count of matched bytes
  877.         jcxz    inpm4           ; z = 0 = mismatch on the initial pattern char
  878.  
  879.         mov     al,tempa        ; port char to find (in case we looped here)
  880. inpm2:  dec     di              ; back up one pattern char
  881.         mov     ah,byte ptr [di]; current pattern character to consider
  882.         call    matchr          ; is port char = earlier pattern char? [js]
  883.         jnc     inpm3           ; nc = equal values, go construct substring
  884.         loop    inpm2           ; do cx times, max. (length of match to date)
  885.         jmp     inpm4           ; get here when there are no matches [js]
  886.  
  887. inpm3:  mov     bx,tempd        ; get last break location
  888.         sub     bx,di           ; displacement = break - new find of port char
  889.         mov     tempd,di        ; remember new location of a port-like char
  890.                                 ; cx has number of chars in test substring
  891.         dec     cx              ; matched one char already [jrs]
  892.         jcxz    inpm3a          ; is there anything left? [jrs]
  893.         call    matstr          ; does this substring match the pattern?
  894.         jc      inpm1           ; c = no match, try making substring smaller
  895.  
  896. inpm3a: mov     di,tempd        ; sub-string matched. Use this shorter match
  897.         mov     temptr,di       ; set di for exit (matstr messes up di)
  898.         inc     temptr          ; matched, point to next pattern char
  899.         jmp     input4          ; continue with fresh port info
  900.  
  901. inpm4:  mov     temptr,offset line; complete failure, restart scanning
  902.         jmp     input4          ; get something from the port
  903.  
  904. ; worker for SCINP
  905. ; compare strings. One starts at offset line, the other starts bx bytes later.
  906. ; cx = # chars to compare. Return carry clear if match, else carry set.
  907. matstr: mov     si,offset line  ; start of pattern string
  908. matstr1:mov     ah,byte ptr [si] ; pattern char
  909.         mov     al,byte ptr [si+bx] ; "old port char" (same as pattern char)
  910.         call    matchr          ; check match of these two characters
  911.         jc      matstr2         ; c = no match (exit with carry flag set)
  912.         inc     si              ; match, consider next pair
  913.         loop    matstr1         ; consider rest of substring (cx is counter)
  914.         clc                     ; clear c bit (substrings do match)
  915. matstr2:ret                     ; preserves flags (c set = no match)
  916.  
  917. ; worker for SCINP
  918. ; compare single characters, one in ah and the other in al. Allow the 0ffh
  919. ; wild card to match CR and LF individually. Return carry clear if match,
  920. ; or carry set if they do not match. Registers preserved.
  921. matchr: cmp     ah,al           ; do these match?
  922.         je      matchr6         ; e = yes
  923.         cmp     ah,0ffh         ; the match cr/lf indicator?
  924.         je      matchr2         ; e = yes
  925.         cmp     al,0ffh         ; the match cr/lf indicator?
  926.         jne     matchr5         ; ne = no match at all.
  927. matchr2:push    ax              ; save both chars again
  928.         and     ah,al           ; make a common byte for testing
  929.         cmp     ah,cr
  930.         je      matchr4         ; e = cr matches 0ffh
  931.         cmp     ah,lf
  932.         je      matchr4         ; e = lf matches 0ffh
  933.         pop     ax              ; recover chars
  934. matchr5:stc                     ; set carry (no match)
  935.         ret
  936. matchr4:pop     ax              ; recover chars
  937. matchr6:clc                     ; clear carry (match)
  938.         ret
  939. SCINP   ENDP
  940. ;
  941. ; Pause for the specified number of seconds or until a time of day
  942. ; Pause [seconds or hh:mm:ss]
  943. ;
  944. SCPAU   PROC    NEAR
  945.         mov     kstatus,0
  946.         mov     ah,cmfile               ; get a word (number)
  947.         mov     dx,offset line          ; where to store it
  948.         mov     byte ptr line,0         ; terminate line incase no text
  949.         mov     bx,offset ptshlp        ; help msg
  950.         call    comnd
  951.          jmp    r
  952.          nop                            ; must be at least 3 bytes
  953.         mov     ah,cmcfm                ; get a confirm
  954.         call    comnd
  955.          jmp    r
  956.          nop
  957.         mov     si,offset line          ; source pointer
  958.         call    inptim                  ; parse pause time (or force default)
  959.         jc      scpau1                  ; c = bad time value
  960.         mov     tempa,0                 ; no modem status to detect
  961.         jmp     swait4                  ; finish in common code
  962. scpau1: ret
  963. SCPAU   ENDP
  964.  
  965. ;
  966. ; Wait for the indicated signal for the specified number of seconds or tod
  967. ; WAIT [seconds] \signal   where \signal is \cd, \dsr modem status lines.
  968. ; Use INPUT-TIMEOUT ACTION for failures.
  969. ;
  970. SCWAIT  PROC    NEAR
  971.         mov     kstatus,0
  972.         mov     ah,cmtxt                ; get a word (number)
  973.         mov     bx,offset line          ; where to store it
  974.         mov     byte ptr line,0         ; terminate line incase no text
  975.         mov     dx,offset wthlp         ; help msg
  976.         call    comnd
  977.          jmp    r
  978.          nop                            ; must be at least 3 bytes
  979.         mov     tempa,0                 ; clear modem status test byte
  980.         mov     si,offset line          ; source pointer
  981.         call    inptim                  ; parse pause time (or force default)
  982.         jc      swait1a                 ; c = bad time value
  983.         mov     di,offset line          ; put text in compare buffer
  984.         call    cnvlin                  ; convert \numbers in buf line
  985.         mov     si,di                   ; code below uses si
  986.         jnc     swait1                  ; nc = no error
  987. swait1a:ret                             ; else return on error
  988. swait1: cmp     cx,0                    ; number of chars to examine
  989.         jle     swait4                  ; le = none
  990.         cld
  991.         lodsb                           ; get a character
  992.         dec     cx                      ; reduce count remaining
  993.         cmp     al,' '                  ; white space?
  994.         jbe     swait1                  ; be = yes, skip over it
  995.         cmp     al,'\'                  ; backslash signal introducer?
  996.         jne     swait1                  ; ne = no, keep searching
  997.         cmp     cx,2                    ; at least two chars in signal?
  998.         jl      swait3                  ; l = no
  999.         mov     ax,[si]
  1000.         or      ax,2020h                ; upper case to lower, two chars
  1001.         cmp     ax,'dc'                 ; carrier detect?
  1002.         jne     swait2                  ; ne = no, try next signal
  1003.         or      tempa,modcd             ; look for the CD bit
  1004.         add     si,2                    ; skip this field
  1005.         sub     cx,2                    ; three less chars left in the line
  1006.         jmp     short swait1            ; continue the scan
  1007. swait2: cmp     ax,'sd'                 ; data set ready?
  1008.         jne     swait3                  ; ne = no
  1009.         mov     al,[si+2]               ; third letter
  1010.         or      al,20h                  ; to lower case
  1011.         cmp     al,'r'                  ; r for dsr?
  1012.         jne     swait3                  ; ne = no
  1013.         or      tempa,moddsr            ; look for the DSR bit
  1014.         add     si,3                    ; skip this field
  1015.         sub     cx,3                    ; four less chars left in the line
  1016. swait3: cmp     ax,'tc'                 ; clear to send?
  1017.         jne     swait3a                 ; ne = no
  1018.         mov     al,[si+2]               ; third letter
  1019.         or      al,20h                  ; to lower case
  1020.         cmp     al,'s'                  ; r for dsr?
  1021.         jne     swait3a                 ; ne = no
  1022.         or      tempa,modcts            ; look for the CTS bit
  1023.         add     si,3                    ; skip this field
  1024.         sub     cx,3                    ; four less chars left in the line
  1025. swait3a:jmp     short swait1            ; continue the scan
  1026.                                         ; SWAIT4 is used by PAUSE command
  1027. SWAIT4: cmp     taklev,0                ; are we in a Take file
  1028.         je      swait5                  ; e = no, print linefeed
  1029.         cmp     flags.takflg,0          ; are commands being echoed
  1030.         je      swait6                  ; e = no, skip this
  1031. swait5: cmp     script.inecho,0         ; Input echoing off?
  1032.         je      swait6                  ; e = yes
  1033.         mov     al,lf                   ; next line
  1034.         call    scdisp                  ; display the char
  1035. swait6: call    serini                  ; initialize the system's serial port
  1036.         jc      swait9                  ; c = failure
  1037.         mov     status,stat_unk         ; clear status flag
  1038.         push    si
  1039.         mov     parmsk,0ffh             ; parity mask, assume 8 bit data
  1040.         mov     si,portval
  1041.         cmp     [si].parflg,parnon      ; parity is none?
  1042.         pop     si
  1043.         je      swait7                  ; e = none
  1044.         mov     parmsk,07fh             ; else strip parity (8th) bit
  1045. swait7: call    getmodem                ; modem handshake status to AL
  1046.         and     al,tempa                ; keep only bits to be tested
  1047.         cmp     tempa,0                 ; anything to be tested?
  1048.         je      swait7a                 ; e = no, just do the wait part
  1049.         cmp     al,tempa                ; check selected status bits
  1050.         jne     swait7a                 ; ne = not all selected bits match
  1051.         jmp     rskp                    ; all match. take successful exit
  1052. swait7a:call    chkport                 ; get and show any new port char
  1053.         call    chkkbd                  ; check keyboard
  1054.         test    status,stat_cc          ; control-c?
  1055.         jnz     swait9                  ; nz = yes, quit
  1056.         call    chktmo                  ; check tod for timeout
  1057.         test    status,stat_tmo+stat_ok ; timeout or user override?
  1058.         jz      swait7                  ; z = no, continue to wait
  1059.         cmp     tempa,0                 ; were we waiting on anything?
  1060.         jne     swait9                  ; ne = yes, timeout = failure
  1061.         jmp     rskp                    ;  else timeout = success
  1062. swait9: or      errlev,2                ; set RECEIVE error condx
  1063.         or      fsta.xstatus,2          ; set status
  1064.         jmp     squit                   ; take error exit
  1065. SCWAIT  ENDP
  1066.  
  1067.  
  1068. ; Output line of text to port, detect \b and \B as commands to send a Break
  1069. ;  on the serial port line.
  1070. ; Output text
  1071.  
  1072. SCOUT   PROC    NEAR
  1073.         mov     kstatus,0
  1074.         mov     ah,cmtxt                ; get a whole line of asciiz text
  1075.         mov     bx,offset line          ; store text here
  1076.         mov     dx,offset outhlp        ; help message
  1077.         call    comnd
  1078.          jmp    r
  1079.          nop
  1080.         cmp     taklev,0                ; is this being done in a Take file?
  1081.         je      outpu0                  ; e = no, display linefeed
  1082.         cmp     flags.takflg,0          ; are commands being echoed?
  1083.         je      outp0a                  ; e = no, skip the display
  1084. outpu0: cmp     script.inecho,0         ; Input echoing off?
  1085.         je      outp0a                  ; e = yes
  1086.         mov     al,lf                   ; next line
  1087.         call    scdisp                  ; display the char
  1088. outp0a: mov     al,spause               ; wait three millisec or more
  1089.         add     al,3
  1090.         xor     ah,ah
  1091.         call    pcwait                  ; breathing space for HDX systems
  1092.         call    serini                  ; initialize the system's serial port
  1093.         jnc     outp0c                  ; nc = success
  1094.         or      errlev,1                ; set SEND failure condition
  1095.         or      fsta.xstatus,1          ; set status
  1096.         jmp     squit
  1097.  
  1098. outp0c: mov     status,stat_unk         ; clear status flag
  1099.         mov     parmsk,0ffh             ; parity mask, assume 8 bit data
  1100.         mov     si,portval
  1101.         cmp     [si].parflg,parnon      ; parity is none?
  1102.         je      outp0b                  ; e = none
  1103.         mov     parmsk,07fh             ; else strip parity (8th) bit
  1104. outp0b: mov     si,portval              ; serial port structure
  1105.         mov     bl,[si].ecoflg          ; Get the local echo flag
  1106.         mov     lecho,bl                ; our copy
  1107.         mov     si,offset line          ; get start of line
  1108.         mov     di,offset line          ; put results in the same place
  1109.         mov     ah,script.incasv        ; save current case state
  1110.         push    ax
  1111.         mov     script.incasv,0ffh      ; say no case conversion
  1112.         call    cnvlin                  ; convert \numbers to binary
  1113.         pop     ax
  1114.         mov     script.incasv,ah        ; recover case state
  1115.         jnc     outpu1                  ; nc = no error
  1116.         ret                             ; return on error
  1117. outpu1: mov     temptr,offset line      ; save pointer here
  1118.         mov     tempd,cx                ; save byte count here
  1119.         mov     ttyact,1                ; say interactive style output
  1120.  
  1121. outpu2: cmp     tempd,0                 ; are we done?
  1122.         jg      outpu2a                 ; g = not done yet
  1123.         mov     ttyact,0                ; reset interactive output flag
  1124.         jmp     rskp                    ; return success
  1125. outpu2a:mov     si,temptr               ; recover pointer
  1126.         cld
  1127.         lodsb                           ; get the character
  1128.         dec     tempd                   ; one less char to send
  1129.         mov     temptr,si               ; save position on line
  1130.         mov     tempa,al                ; save char here for outchr
  1131.         mov     retry,0                 ; number of output retries
  1132.         cmp     al,5ch                  ; backslash?
  1133.         jne     outpu4d                 ; ne = no
  1134.         cmp     byte ptr [si],'b'       ; "\b" for Break?
  1135.         je      outpu4c                 ; e = yes
  1136.         cmp     byte ptr [si],'B'       ; "\B" ?
  1137.         jne     outpu4d                 ; ne = no
  1138. outpu4c:inc     temptr                  ; move scan ptr beyond "\b"
  1139.         dec     tempd
  1140.         call    sendbr                  ; call msx send-a-break procedure
  1141.         jmp     outpu5                  ; resume beyond echoing
  1142.  
  1143. outpu4d:inc     retry                   ; count output attempts
  1144.         cmp     retry,maxtry            ; too many retries?
  1145.         jle     outpu4g                 ; le = no
  1146.         or      errlev,1                ; set SEND failure condition
  1147.         or      fsta.xstatus,1          ; set status
  1148.         jmp     squit                   ; return failure
  1149. outpu4g:mov     ah,tempa                ; outchr gets fed from ah
  1150.         call    outchr                  ; send the character to the port
  1151.          jmp     outpu4d                ; failure to send char
  1152.          nop                            ; ensure 3 bytes for rskp of outchr
  1153.         cmp     lecho,0                 ; is Local echo active?
  1154.         je      outpu5                  ; e = no
  1155.         mov     al,tempa                ;
  1156.         test    flags.capflg,logses     ; is capturing active?
  1157.         jz      outp4b                  ; z = no
  1158.         push    ax                      ; save char
  1159.         call    cptchr                  ; give it captured character
  1160.         pop     ax                      ; restore character and keep going
  1161. outp4b: cmp     script.inecho,0         ; Input echo off?
  1162.         je      outpu5                  ; e = yes
  1163.         call    scdisp                  ; echo character to the screen
  1164.                                         ;
  1165. outpu5: push    cx
  1166. outpu5a:mov     cx,10                   ; reset retry counter
  1167. outpu5b:call    chkkbd                  ; check keyboard for interruption
  1168.         test    status,stat_cc          ; control c interrupt?
  1169.         jnz     outpu6                  ; nz = yes, quit now
  1170.         cmp     script.inecho,0         ; Input echo off?
  1171.         je      outpu5c                 ; e = yes, skip port reading/display
  1172.         call    chkport                 ; check for char at serial port
  1173.         test    status,stat_ok          ;   and put any in buffer
  1174.         jnz     outpu5a                 ; nz = have a char, look for another
  1175.         mov     ax,1                    ; wait 1 millisec between rereads
  1176.         push    cx                      ; protect counter
  1177.         call    pcwait
  1178.         pop     cx
  1179.         dec     cx                      ; count down retries
  1180.         jge     outpu5b                 ; ge = keep trying
  1181. outpu5c:pop     cx                      ; no more input, recover register
  1182.         jmp     outpu2                  ; resume command
  1183. outpu6: pop     cx                      ; recover register
  1184.         or      errlev,1                ; set SEND failure condition
  1185.         or      fsta.xstatus,1          ; set status
  1186.         mov     ttyact,0                ; reset interactive output flag
  1187.         jmp     squit                   ; quit on control c
  1188. SCOUT   ENDP
  1189.  
  1190.  
  1191. ; Raw file transfer to host (strips linefeeds)
  1192. ; Transmit filespec [prompt]
  1193. ; Optional prompt is the single char expected from the host to ACK each line.
  1194. ; Default prompt is a linefeed (or a carriage return from us).
  1195. ;
  1196. SCXMIT  PROC    NEAR
  1197.         mov     kstatus,0
  1198.         mov     ah,cmfile               ; get a filename, asciiz
  1199.         mov     dx,offset line          ; where to store it
  1200.         mov     bx,offset xmthlp        ; help message
  1201.         call    comnd
  1202.          jmp    r                       ; exit on failure
  1203.          nop
  1204.         mov     ah,cmtxt                ; get a prompt string, asciiz
  1205.         mov     bx,offset line+80       ; where to keep it (end of "line")
  1206.         mov     word ptr [bx],0         ; clear and add terminator
  1207.         mov     dx,offset pmthlp        ; Help in case user types "?".
  1208.         call    comnd
  1209.          jmp    r
  1210.          nop
  1211.         cmp     line,0                  ; filename given?
  1212.         je      xmit0a                  ; e = no
  1213.         cmp     ah,0                    ; prompt given?
  1214.         je      xmit0b                  ; e = no, use line feed default
  1215.         mov     si,offset line+80       ; convert possible numeric prompt
  1216.         call    katoi                   ; convert number to binary, if number
  1217.         jnc     xmit0                   ; nc = got number
  1218.         mov     al,line+80              ; get ascii char from user's prompt
  1219.         jmp     short xmit0
  1220. xmit0b: mov     al,lf                   ; default prompt
  1221. xmit0:  mov     tempa,al                ; save the code here
  1222.         mov     dx,offset line          ; point to filename
  1223.         mov     ah,open2                ; DOS 2 open file
  1224.         mov     al,0                    ; open for reading
  1225.         int     dos
  1226.         mov     fhandle,ax              ; store file handle here
  1227.         jnc     xmit1                   ; nc = successful opening
  1228.  
  1229. xmit0a: mov     ah,prstr                ; give file not found error message
  1230.         mov     dx,offset xfrfnf
  1231.         int     dos
  1232.         or      errlev,1                ; set SEND failure condition
  1233.         or      fsta.xstatus,1          ; set status
  1234.         jmp     squit                   ; exit failure
  1235.  
  1236. xmitx:  mov     ah,prstr                ; error during transfer
  1237.         mov     dx,offset xfrrer
  1238.         int     dos
  1239. xmitx2: mov     bx,fhandle              ; file handle
  1240.         mov     ah,close2               ; close file
  1241.         int     dos
  1242. ;;      call    serrst                  ; reset serial port
  1243.         call    bufclear                ; clear script buffer
  1244.         call    clrbuf                  ; clear local serial port buffer
  1245.         or      errlev,1                ; set SEND failure condition
  1246.         or      fsta.xstatus,1          ; set status
  1247.         jmp     squit                   ; exit failure
  1248.                                         ;
  1249. xmity:  mov     bx,fhandle              ; file handle
  1250.         mov     ah,close2               ; close file
  1251.         int     dos
  1252. ;;      call    serrst                  ; reset serial port
  1253.         call    bufclear                ; clear buffers
  1254.         call    clrbuf
  1255.         jmp     rskp                    ; and return success
  1256.  
  1257. xmit1:  call    serini                  ; initialize serial port
  1258.         jnc     xmit1b                  ; nc = success
  1259.         or      errlev,1                ; set SEND failure condition
  1260.         or      fsta.xstatus,1          ; set status
  1261.         jmp     squit
  1262.  
  1263. xmit1b: call    bufclear                ; clear script input buffer
  1264.         call    clrbuf                  ; clear serial port buffer
  1265.         mov     status,stat_unk         ; clear status flag
  1266.         mov     parmsk,0ffh             ; parity mask, assume 8 bit data
  1267.         mov     si,portval
  1268.         cmp     [si].parflg,parnon      ; parity is none?
  1269.         je      xmit1a                  ; e = none
  1270.         mov     parmsk,07fh             ; else strip parity (8th) bit
  1271. xmit1a: mov     bl,[si].ecoflg          ; Get the local echo flag.
  1272.         mov     lecho,bl                ; our copy
  1273.         mov     dx,offset crlf          ; display cr/lf
  1274.         mov     ah,prstr
  1275.         int     dos
  1276.  
  1277. xmit2:  mov     dx,offset line          ; buffer to read into
  1278.         mov     cx,linelen              ; # of bytes to read
  1279.         mov     ah,readf2               ; read bytes from file
  1280.         mov     bx,fhandle              ; file handle is stored here
  1281.         int     dos
  1282.         jnc     xmit2a                  ; nc = success
  1283.         jmp     xmitx                   ; exit failure
  1284. xmit2a: mov     cx,ax                   ; number of bytes read
  1285.         jcxz    xmity                   ; z = none, end of file
  1286.                                         ;
  1287.         mov     si,offset line          ; buffer for file reads
  1288.         cld
  1289. xmit3:  lodsb                           ; get a byte
  1290.         cmp     al,ctlz                 ; is this a Control-Z?
  1291.         jne     xmit3a                  ; ne = no
  1292.         cmp     flags.eofcz,0           ; ignore Control-Z as EOF?
  1293.         jne     xmity                   ; ne = no, we are at EOF
  1294. xmit3a: push    si                      ; save position on line
  1295.         push    cx                      ; and byte count
  1296.         push    ax                      ; save char around outchr call
  1297. xmit4:  mov     retry,0                 ; clear retry counter
  1298. xmit4f: pop     ax                      ; recover saved char
  1299.         push    ax                      ; and save it again
  1300.         mov     ah,al                   ; outchr wants char in ah
  1301.         inc     retry                   ; count number of attempts
  1302.         cmp     retry,maxtry            ; too many retries?
  1303.         jle     xmit4g                  ; le = no
  1304.         or      status,stat_cc          ; simulate control-c abort
  1305.         pop     ax                      ; clean stack
  1306.         xor     al,al                   ; clear char
  1307.         jmp     xmita                   ; and abort transfer
  1308. xmit4g: cmp     al,lf                   ; line feed?
  1309.         je      xmit4h                  ; e = yes, don't send it
  1310.         call    outchr                  ; send the character to the port
  1311.          jmp     xmit4f                 ; failed, try again
  1312.          nop
  1313. xmit4h: pop     ax                      ; recover saved char
  1314.         cmp     lecho,0                 ; is local echoing active?
  1315.         je      xmit5                   ; e = no
  1316.         test    flags.capflg,logses     ; capturing active?
  1317.         jz      xmit4a                  ; z = no
  1318.         push    ax                      ; save char
  1319.         call    cptchr                  ; give it the character just sent
  1320.         pop     ax                      ; restore character and keep going
  1321. xmit4a: call    scdisp                  ; display char on screen
  1322.  
  1323. xmit5:  cmp     al,cr                   ; did we send a carriage return?
  1324.         je      xmit8                   ; e = yes, time to check keyboard
  1325.  
  1326. xmit7:  pop     cx
  1327.         pop     si
  1328.         loop    xmit3                   ; finish this buffer full
  1329.         jmp     xmit2                   ; read next buffer
  1330.  
  1331. xmit8:  test    status,stat_cc          ; Control-C seen?
  1332.         jnz     xmita                   ; nz = yes
  1333.         call    chkkbd                  ; check keyboard (returns char in al)
  1334.         test    status,stat_ok          ; have a char?
  1335.         jnz     xmita                   ; nz = yes
  1336.         cmp     tempa,0                 ; is prompt char a null?
  1337.         jne     xmit8b                  ; ne = no
  1338.         call    bufread                 ; check for char from serial port buf
  1339.         jnc     xmit8                   ; nc = a char, read til none
  1340.         jmp     xmit7                   ; continue transfer
  1341. xmit8b: call    bufread                 ; check for char from serial port buf
  1342.         jc      xmit8                   ; c = none
  1343.         cmp     al,tempa                ; is port char the ack?
  1344.         jne     xmit8                   ; ne = no, just ignore the char
  1345.         jmp     xmit7                   ; yes, continue transfer
  1346.  
  1347. xmita:  test    status,stat_cc          ; control-c?
  1348.         jnz     xmitc                   ; nz = yes
  1349.         test    status,stat_cr          ; a local ack?
  1350.         jz      xmit8                   ; no, ignore local char
  1351.         mov     dx,offset crlf          ; display cr/lf
  1352.         mov     ah,prstr
  1353.         int     dos
  1354.         jmp     xmit7                   ; continue transfer
  1355. xmitc:  pop     cx                      ; Control-C, clear stack
  1356.         pop     si                      ; ...
  1357.         mov     dx,offset xfrcan        ; say canceling transfer
  1358.         mov     ah,prstr
  1359.         int     dos
  1360.         mov     flags.cxzflg,0          ; clear Control-C flag
  1361.         jmp     xmitx2                  ; ctrl-c, quit
  1362.  
  1363. SCXMIT  ENDP
  1364.  
  1365. ;;;;;;;;;;;;;;;;;; local support procedures ;;;;;;;;;;
  1366. ;
  1367. ;worker: copy line from si to di, converting \nnn strings to single chars
  1368. ; returns carry set if error, else carry clear. Detects leading at-sign
  1369. ; as an indicator to read command file for one line of text; command files
  1370. ; may be nested to a depth of 100.
  1371. ; Items of the form \chars which are not numbers are copied verbatium
  1372. ; to the output string (ex: \a  is copied as \a). The string is first trimmed
  1373. ; of trailing spaces, then the possible curly brace delimiter pair is
  1374. ; removed, and finally \numbers are converted to binary. [jrd]
  1375. cnvlin  proc    near
  1376.         push    si                      ; source ptr
  1377.         push    di                      ; destination ptr
  1378.         push    ax
  1379.         mov     ax,ds
  1380.         mov     es,ax                   ; use data segment for es:di
  1381.         pop     ax
  1382.         mov     tempd,0                 ; count indirection depth
  1383. cnvln0: cmp     tempd,100               ; limit to 100 deep
  1384.         jbe     cnvln0a                 ; be = not too deep yet
  1385.         jmp     cnvln8                  ; too deep, quit
  1386. cnvln0a:cld
  1387.         xor     cx,cx                   ; initialize returned byte count
  1388.         lodsb                           ; get the first character
  1389.         cmp     al,40h                  ; at-sign indirection?
  1390.         je      cnvln5                  ; e = yes, open the file
  1391.         dec     si                      ; no, push back char just read
  1392.         call    cnvstr                  ; convert string's curly braces
  1393. cnvln1: xor     ah,ah                   ; clear high byte of number
  1394.         call    katoi                   ; get a char into al, convert number
  1395.         jnc     cnvln4                  ; nc = binary number converted
  1396.         cmp     al,0ffh                 ; cr/lf wild card?
  1397.         je      cnvln4                  ; e = yes, store it
  1398.         cmp     al,0                    ; end of line?
  1399.         jne     cnvln3                  ; ne = no
  1400.         jmp     cnvlnx                  ; yes, exit now
  1401. cnvln3: cmp     al,'a'                  ; candidate for conversion? [js]
  1402.         jb      cnvln4                  ; b = no
  1403.         cmp     al,'z'                  ; still in lower case set? [js]
  1404.         ja      cnvln4                  ; a = no
  1405.         and     al,script.incasv        ; else apply case conversion mask
  1406. cnvln4: stosb                           ; save the char
  1407.         inc     cx                      ; and count it
  1408.         cmp     ah,0                    ; was number larger than one byte?
  1409.         je      cnvln1                  ; e = no
  1410.         xchg    ah,al                   ; put high byte into al
  1411.         stosb                           ; store it too
  1412.         inc     cx                      ; count storage
  1413.         jmp     short cnvln1            ; read more
  1414.  
  1415. cnvln5: mov     dx,si                   ; get filename ptr from source line
  1416.         push    si
  1417.         inc     tempd                   ; count indirection depth
  1418.         mov     cx,64                   ; max length of a filename.
  1419. cnvln5a:cmp     byte ptr [si],' '       ; whitespace or control code?
  1420.         jbe     cnvln5b                 ; be = yes, found termination
  1421.         inc     si                      ; else look at next char
  1422.         loop    cnvln5a                 ; limit search
  1423. cnvln5b:mov     byte ptr [si],0         ; make asciiz
  1424.         pop     si
  1425.         mov     ah,open2                ; DOS 2 open file
  1426.         mov     al,0                    ; open for reading
  1427.         int     dos
  1428.         mov     word ptr fhandle,ax     ; store file handle
  1429.         jnc     cnvln7                  ; nc = open ok, read from file
  1430.  
  1431.         mov     ah,prstr
  1432.         mov     dx,offset indmis        ; file open error msg
  1433.         int     dos
  1434.         xor     cx,cx                   ; say zero bytes read
  1435.         pop     di                      ; destination ptr
  1436.         pop     si                      ; source ptr
  1437.         stc                             ; set c bit, failure
  1438.         ret
  1439.  
  1440. cnvln7: mov     bx,word ptr fhandle     ; file handle
  1441.         mov     cx,linelen              ; # of bytes to read
  1442.         mov     ah,ioctl                ; ioctl, is this the console device?
  1443.         mov     al,0                    ; get device info
  1444.         int     dos
  1445.         and     dl,81h                  ; ISDEV and ISCIN bits needed together
  1446.         cmp     dl,81h                  ; Console input device?
  1447.         jne     cnvln7d                 ; ne = no, use regular file i/o
  1448.         push    ds
  1449.         pop     es                      ; set es:di to datas segment
  1450.         push    di                      ; save starting pointer
  1451. cnvln7b:mov     ah,coninq               ; read console, no echo
  1452.         int     dos
  1453.         stosb
  1454.         cmp     al,cr                   ; end of the line yet?
  1455.         loopne  cnvln7b                 ; keep reading
  1456. cnvln7c:mov     byte ptr [di],0         ; insert terminator
  1457.         pop     di                      ; recover starting pointer
  1458.         mov     dx,di                   ; simulate read file read
  1459.         mov     ax,linelen
  1460.         sub     ax,cx                   ; ax = number of chars read
  1461.         jmp     cnvln7e                 ; close file, finish processing
  1462.  
  1463. cnvln7d:mov     dx,di                   ; destination ptr
  1464.         mov     byte ptr [di],0         ; insert null terminator, clears line
  1465.         mov     ah,readf2               ; DOS 2 read from file
  1466.         int     dos
  1467. cnvln7e:pushf                           ; save flags
  1468.         push    ax                      ; save byte count read
  1469.         mov     ah,close2               ; close file (wanted just one line)
  1470.         int     dos
  1471.         pop     ax
  1472.         popf                            ; recover flags now
  1473.         jc      cnvln8                  ; c = error
  1474.         mov     cx,ax                   ; ax = number of bytes read
  1475.         jcxz    cnvln8a                 ; cx = z = no bytes read
  1476.         mov     al,cr                   ; look for cr as terminator
  1477.         cld
  1478.         repne   scasb                   ; scan while not a cr and cx not zero
  1479.         jne     cnvln7a                 ; ne = no cr found
  1480.         dec     di                      ; point at cr
  1481. cnvln7a:mov     byte ptr [di],0         ; plant terminator on the cr
  1482.                                         ;  or after last read char, if no cr.
  1483.         pop     di                      ; get original destination ptr
  1484.         push    di                      ; and save it again
  1485.         mov     si,dx                   ; new source = this line
  1486.                                         ; go convert text, as necessary, and
  1487.         jmp     cnvln0                  ;  allow nested indirection
  1488.  
  1489. cnvln8: mov     ah,prstr
  1490.         mov     dx,offset inderr        ; error reading file message
  1491.         int     dos
  1492. cnvln8a:xor     cx,cx                   ; say zero bytes read
  1493.         pop     di
  1494.         pop     si
  1495.         stc                             ; set carry for failure
  1496.         ret                             ; and do a real return
  1497.  
  1498. cnvlnx: pop     di                      ; destination ptr
  1499.         pop     si                      ; source ptr
  1500.         clc                             ; clear c bit, success
  1501.         ret
  1502. cnvlin  endp
  1503. ;
  1504. ; worker: read the number of seconds to pause or timeout
  1505. ;    returns time of day for timeout in timhms, and next non-space or
  1506. ;    non-tab source char ptr in si. Time is either elapsed seconds or
  1507. ;    a specific hh:mm:ss, determined from context of colons being present.
  1508. ;    Last form can be abbreviated as hh:[mm[:ss]]. Returns carry set if
  1509. ;    hh:mm:ss form has bad construction (invalid time).
  1510. inptim  proc    near
  1511.         push    ax
  1512.         push    bx
  1513.         push    cx
  1514.         push    dx
  1515.         push    di
  1516.         cld                             ; decode pure seconds construction
  1517.         mov     di,si                   ; remember source pointer
  1518.         mov     cx,10                   ; multiplier
  1519.         mov     bx,script.indfto        ; no numbers yet, use default-timeout
  1520.         mov     al,byte ptr[si]
  1521.         cmp     al,':'                  ; stray hh:mm:ss separator?
  1522.         je      inptm8                  ; e = yes
  1523.         cmp     al,'9'                  ; start with numeric input?
  1524.         ja      inptm4                  ; a = no, use default time
  1525.         cmp     al,'0'                  ; ditto
  1526.         jb      inptm4
  1527.         xor     ah,ah                   ; source char holder
  1528.         xor     bx,bx                   ; accumulated sum
  1529. inptm1: mov     al,byte ptr[si]         ; get a byte into al
  1530.         cmp     al,':'                  ; hh:mm:ss construction?
  1531.         je      inptm8                  ; e = yes
  1532.         sub     al,'0'                  ; remove ascii bias
  1533.         cmp     al,9                    ; numeric?
  1534.         ja      inptm4                  ; a = non-numeric, exit loop, bx = sum
  1535.         xchg    ax,bx                   ; put sum into ax, char in bl
  1536.         mul     cx                      ; sum times ten
  1537.         xchg    ax,bx                   ; put char into al, sum in bx
  1538.         add     bx,ax                   ; add to sum
  1539.         inc     si                      ; next char
  1540.         jmp     short inptm1            ; loop thru all chars
  1541.  
  1542. inptm4: cmp     bx,12*60*60             ; half a day, in seconds
  1543.         jb      inptm5                  ; b = less than
  1544.         jmp     inptm13                 ; more than, error
  1545. inptm5: push    si                      ; save ending scan position for return
  1546.         mov     timout,bx               ; # seconds of timeout desired
  1547.         mov     ah,gettim               ; read DOS tod clock
  1548.         int     dos
  1549.         mov     timhms[0],ch            ; hours
  1550.         mov     timhms[1],cl            ; minutes
  1551.         mov     timhms[2],dh            ; seconds
  1552.         mov     timhms[3],dl            ; hundredths of seconds
  1553.         mov     bx,2                    ; start with seconds field
  1554. inptm6: mov     ax,timout               ; our desired timeout interval
  1555.         add     al,timhms[bx]           ; add current tod digit to interval
  1556.         adc     ah,0
  1557.         xor     dx,dx                   ; clear high order part thereof
  1558.         mov     cx,60                   ; divide by 60
  1559.         div     cx                      ; compute number of minutes or hours
  1560.         mov     timout,ax               ; quotient
  1561.         mov     timhms[bx],dl           ; put remainder in timeout tod digit
  1562.         dec     bx                      ; look at next higher order time field
  1563.         cmp     bx,0                    ; done all time fields?
  1564.         jge     inptm6                  ; ge = no
  1565.         cmp     timhms[0],24            ; normalize hours
  1566.         jl      inptm7                  ; l = not 24 hours
  1567.         sub     timhms[0],24            ; discard part over 24 hours
  1568. inptm7: pop     si                      ; return ptr to next source char
  1569.         jmp     inptm11                 ; trim trailing whitespace
  1570.  
  1571. inptm8:                                 ; decode hh:[mm[:ss]] to timhms
  1572.         mov     si,di                   ; recall starting source pointer
  1573.         mov     word ptr timhms[0],0    ; clear time out tod
  1574.         mov     word ptr timhms[2],0
  1575.         mov     bx,0                    ; three groups possible
  1576. inptm9: mov     dl,byte ptr[si]         ; get a char
  1577.         cmp     dl,':'                  ; field separator?
  1578.         je      inptm10                 ; e = a separator, step fields
  1579.         sub     dl,'0'                  ; remove ascii bias
  1580.         cmp     dl,9
  1581.         ja      short inptm11           ; a = failure to get expected digit
  1582.         mov     al,timhms[bx]           ; get sum to al
  1583.         mov     ah,10
  1584.         mul     ah                      ; sum times ten
  1585.         add     al,dl                   ; sum = 10 * previous + current
  1586.         mov     timhms[bx],al           ; current sum
  1587.         cmp     timhms[bx],60           ; more than legal?
  1588.         jae     inptm13                 ; ae = illegal
  1589.         cmp     bx,0                    ; doing hours?
  1590.         ja      inptm9a                 ; a = no, min or sec
  1591.         cmp     timhms[bx],24           ; more than legal?
  1592.         jae     inptm13                 ; ae = illegal
  1593. inptm9a:inc     si                      ; next char
  1594.         jmp     short inptm9            ; continue analysis
  1595. inptm10:inc     bx                      ; point to next field
  1596.         inc     si                      ; next char
  1597.         cmp     bx,2                    ; last subscript to use (secs)
  1598.         jbe     inptm9                  ; be = get more text
  1599.  
  1600. inptm11:cmp     byte ptr [si],spc       ; examine break char, remove spaces
  1601.         jne     inptm12                 ; ne = no, stay at this char
  1602.         inc     si                      ; look at next char
  1603.         jmp     short inptm11           ; continue scanning off white space
  1604. inptm12:clc                             ; carry clear for success
  1605.         jnc     inptm14
  1606. inptm13:stc                             ; carry set for illegal value
  1607. inptm14:pop     di                      ; return with si beyond our text
  1608.         pop     dx
  1609.         pop     cx
  1610.         pop     bx
  1611.         pop     ax
  1612.         ret
  1613. inptim  endp
  1614.  
  1615. ; worker: display the char in al on screen
  1616. ; use caret-char notation for control codes
  1617. scdisp  proc    near
  1618.         push    dx
  1619.         push    ax
  1620.         mov     ah,conout               ; our desired function
  1621.         test    flags.remflg,d8bit      ; show all 8 bits?
  1622.         jnz     scdisp0                 ; nz = yes
  1623.         and     al,7fh                  ; apply 7 bit display mask
  1624. scdisp0:cmp     al,0                    ; null?
  1625.         je      scdis2                  ; e = yes, ignore
  1626.         cmp     al,del                  ; delete code?
  1627.         je      scdis2                  ; e = yes, ignore
  1628.         cmp     al,spc                  ; control char?
  1629.         jae     scdis1                  ; ae = no, display as-is
  1630.         cmp     al,cr                   ; carriage return?
  1631.         je      scdis1                  ; e = yes, display as-is
  1632.         cmp     al,lf                   ; line feed?
  1633.         je      scdis1
  1634.         cmp     al,tab                  ; horizontal tab?
  1635.         je      scdis1
  1636.         cmp     al,bell                 ; bell?
  1637.         je      scdis1
  1638.         cmp     al,bs                   ; backspace?
  1639.         je      scdis1
  1640.         cmp     al,escape               ; escape?
  1641.         je      scdis1
  1642.         or      al,40h                  ; control code to printable char
  1643.         push    ax
  1644.         mov     dl,5eh                  ; display caret first
  1645.         int     dos
  1646.         pop     ax
  1647. scdis1: mov     dl,al                   ; the char to be displayed
  1648.         int     dos
  1649. scdis2: pop     ax
  1650.         pop     dx
  1651.         ret
  1652. scdisp  endp
  1653.  
  1654. ; workers
  1655. ; Circular buffer for data from serial port. Written by Joe R. Doupnik
  1656. ; Entry points -
  1657. ;       bufread: read serial port for latest char (invokes bufwrite, sets
  1658. ;                       status), get a char into al, return carry set if none.
  1659. ;       bufwrite: put a char from al into buf. If this overwrites an unread
  1660. ;                       character then: we lose the old char, the read pointer
  1661. ;                       is moved to the next oldest unread char, and the
  1662. ;                       number of chars in the buffer is decreased by one.
  1663. ;       bufclear: empties the buffer.
  1664. ; The buffer is prtbuf, of size prtbuflen bytes. Internally, integer bufcnt
  1665. ; holds the number of buffer locations occupied, pointer bufrdptr is the
  1666. ; offset of the char to be read, pointer bufwtptr is the offset of the
  1667. ; place to store the next incoming char.
  1668. ;
  1669. bufclear proc   near
  1670.         mov     bufcnt,0                ; clear count of bytes in buffer
  1671.         mov     bufrdptr,offset prtbuf  ; move read pointer to start of buf
  1672.         mov     bufwtptr,offset prtbuf  ; move write pointer to start of buf
  1673.         mov     cx,prtbuflen
  1674.         push    es                      ; physically clear the buffer
  1675.         push    di
  1676.         mov     ax,datas
  1677.         mov     es,ax
  1678.         mov     al,0                    ; write prtbuflen nulls
  1679.         mov     di,offset prtbuf
  1680.         cld
  1681.         rep     stosb
  1682.         pop     di
  1683.         pop     es
  1684.         ret
  1685. bufclear endp
  1686.  
  1687. bufread proc    near
  1688.         call    chkport                 ; get any oldest char from port
  1689.         cmp     bufcnt,0                ; empty buffer?
  1690.         jne     bufrd1                  ; ne = no
  1691.         stc                             ; yes, set carry flag (no char)
  1692.         ret                             ; and quit (chkport sets status)
  1693. bufrd1: push    si
  1694.         mov     si,bufrdptr
  1695.         mov     al,byte ptr [si]        ; extract a char into al
  1696.         pop     si
  1697.         inc     bufrdptr                ; move pointer to next byte
  1698.         dec     bufcnt                  ; say have extracted a char
  1699.         cmp     bufrdptr,offset prtbuf+prtbuflen        ; beyond end?
  1700.         jb      bufrd2                  ; b = not yet, just return
  1701.         mov     bufrdptr,offset prtbuf  ; reset to start of buf (wrapping)
  1702. bufrd2: clc                             ; clear carry flag (have read a char)
  1703.         ret                             ; chkport sets status
  1704. bufread endp
  1705.  
  1706. ; Non-destructive read of serial port circular buffer. Requires external
  1707. ; initialization of peek read pointer bufpkptr and count remaining bufpkcnt.
  1708. ; Returns character in register al.
  1709. peekbuf proc    near
  1710.         cmp     bufpkcnt,0              ; peek counter, empty buffer?
  1711.         jne     peekbu2                 ; ne = no, so look in buffer
  1712.         cmp     bufcnt,prtbuflen        ; is real buffer full?
  1713.         jae     peekbu1                 ; ae = yes, have examined everything
  1714.         call    chkport                 ; get a char from port
  1715.         cmp     bufcnt,0                ; still nothing from port?
  1716.         je      peekbu1                 ; e = no char, report fact
  1717.         inc     bufpkcnt                ; got one, increase peek counter
  1718.         jmp     peekbu2                 ; go extract it
  1719. peekbu1:stc                             ; return nothing to see
  1720.         ret
  1721. peekbu2:push    si
  1722.         mov     si,bufpkptr             ; buffer peek pointer
  1723.         mov     al,byte ptr [si]        ; extract a char into al
  1724.         pop     si
  1725.         inc     bufpkptr                ; move pointer to next byte
  1726.         dec     bufpkcnt                ; say have extracted a char
  1727.         cmp     bufpkptr,offset prtbuf+prtbuflen        ; beyond end?
  1728.         jb      peekbu3                 ; b = not yet, just return
  1729.         mov     bufpkptr,offset prtbuf  ; reset to start of buf (wrapping)
  1730. peekbu3:clc                             ; clear carry flag (have read a char)
  1731.         ret
  1732. peekbuf endp
  1733.  
  1734. bufwrite proc   near
  1735.         push    si
  1736.         mov     si,bufwtptr
  1737.         mov     byte ptr [si],al        ; store char held in al
  1738.         pop     si
  1739.         inc     bufwtptr                ; move pointer to next byte
  1740.         cmp     bufwtptr,offset prtbuf+prtbuflen        ; beyond end?
  1741.         jb      bufwt1                  ; b = not yet
  1742.         mov     bufwtptr,offset prtbuf  ; reset to start of buf (wrapping)
  1743. bufwt1: inc     bufcnt                  ; say have added a char to the buf
  1744.         cmp     bufcnt,prtbuflen        ; more than we can hold?
  1745.         jbe     bufwt3                  ; be = not overflowing
  1746.         push    bufwtptr                ; read ptr can't alias write ptr
  1747.         pop     bufrdptr                ; move up read pointer
  1748.         mov     bufcnt,prtbuflen        ; limit count to max buffer length
  1749. bufwt3: ret
  1750. bufwrite endp
  1751.  
  1752. ; worker: check for timeout, return status=stat_tmo if timeout, else bit
  1753. ;  stat_tmo is cleared.
  1754. chktmo: and     status,not stat_tmo
  1755.         mov     ah,gettim               ; get the time of day
  1756.         int     dos
  1757.         sub     ch,timhms[0]            ; hours difference, ch = (now-timeout)
  1758.         je      chktmo2                 ; e = same, check mmss.s
  1759.         jg      chktmo1                 ; g = past target hour
  1760.         add     ch,24                   ; we are early, see by how much
  1761. chktmo1:cmp     ch,12                   ; hours difference, large or small?
  1762.         jge     chktmox                 ; ge = not that time yet
  1763.         jl      chktmo3                 ; l = beyond that time
  1764. chktmo2:cmp     cl,timhms[1]            ; minutes, hours match
  1765.         jb      chktmox                 ; b = early
  1766.         ja      chktmo3                 ; a = late
  1767.         cmp     dh,timhms[2]            ; seconds, hhmm match
  1768.         jb      chktmox                 ; b = early
  1769.         ja      chktmo3                 ; a = late
  1770.         cmp     dl,timhms[3]            ; fractions, hhmmss match
  1771.         jb      chktmox                 ; b = early
  1772. chktmo3:or      status,stat_tmo         ; say timeout
  1773.         stc
  1774.         ret
  1775. chktmox:clc
  1776.         ret
  1777. ;
  1778. ; worker: check keyboard for char. Return status = stat_cc if control-C typed,
  1779. ; stat_cr if carriage return, or stat_ok if any other char typed. Else return
  1780. ; with these status bits cleared.
  1781. chkkbd: and     status,not (stat_ok+stat_cc+stat_cr) ; clear status bits
  1782.         cmp     flags.cxzflg,'C'        ; Control-C interrupt seen?
  1783.         je      chkkbd0                 ; e = yes
  1784.         call    isdev                   ; is stdin a device, not disk file?
  1785.         jnc     chkkbd2                 ; nc = not device so do not read here
  1786.         mov     ah,dconio               ; keyboard char present?
  1787.         mov     dl,0ffH
  1788.         int     dos
  1789.         je      chkkbd1                 ; e = none
  1790.         or      status,stat_ok          ; have a char, return it in al
  1791.         cmp     al,3                    ; control c?
  1792.         jne     chkkbd1                 ; ne = not control c
  1793. chkkbd0:or      status,stat_cc          ; say control c
  1794. chkkbd1:cmp     al,cr                   ; carriage return? [js]
  1795.         jne     chkkbd2                 ; ne = no
  1796.         or      status,stat_cr          ; say carriage return [js]
  1797. chkkbd2:ret
  1798. ;
  1799. ; worker: check serial port for received char. Return status = stat_ok if
  1800. ;  char received, otherwise stat_ok cleared. Can echo char to screen. Will
  1801. ;  write char to local circular buffer.
  1802. chkport:and     status,not stat_ok      ; clear status bit
  1803.         call    prtchr                  ; char at port (in al)?
  1804.          jmp    chkpor1                 ; yes, analyze it
  1805.          nop                            ; ensure 3 bytes for rskp of prtchr
  1806.         ret                             ; no, return
  1807. chkpor1:and     al,parmsk               ; strip parity, if any
  1808.         cmp     rxtable+256,0           ; is translation turned off?
  1809.         je      chkpor0                 ; e = yes, no translation
  1810.         push    bx                      ; translate incoming character
  1811.         mov     bx,offset rxtable       ; the translation table
  1812.         xlatb
  1813.         pop     bx
  1814. chkpor0:test    flags.capflg,logses     ; capturing active?
  1815.         jz      chkpor3                 ; z = no
  1816.         test    flags.remflg,d8bit      ; keep 8 bits for displays?
  1817.         jnz     chkpo0a                 ; nz = yes, 8 bits if possible
  1818.         cmp     flags.debug,0           ; is debug mode active?
  1819.         jne     chkpo0a                 ; ne = yes, record 8 bits
  1820.         and     al,7fh                  ; remove high bit
  1821. chkpo0a:push    ax                      ; save char
  1822.         call    cptchr                  ; give it captured character
  1823.         pop     ax                      ; restore character and keep going
  1824. chkpor3:test    flags.remflg,d8bit      ; keep 8 bits for displays?
  1825.         jnz     chkpo3a                 ; nz = yes, 8 bits if possible
  1826.         and     al,7fh                  ; remove high bit
  1827. chkpo3a:cmp     script.inecho,0         ; input echoing off?
  1828.         je      chkpor4                 ; e = yes
  1829.         call    scdisp                  ; display the char
  1830. chkpor4:call    bufwrite                ; put char in buffer
  1831.         or      status,stat_ok          ; say have a char (still in al)
  1832.         ret
  1833. ;
  1834. ; Squit is the script error exit pathway.
  1835. ;
  1836. squit:  mov     kstatus,2               ; general command status, failure
  1837.         test    status,stat_tmo         ; timeout?
  1838.         jz      squit2                  ; z = no, another kind of failure
  1839.         cmp     taklev,0                ; in a Take/macro?
  1840.         jne     squit1                  ; ne = yes, skip timeout message
  1841.         push    dx
  1842.         mov     dx,offset tmomsg        ; say timed out
  1843.         mov     ah,prstr
  1844.         int     dos                     ; display it.
  1845.         pop     dx
  1846. squit1: cmp     script.inactv,0         ; action to do upon timeout
  1847.         je      squit4                  ; 0 = proceed, ne = non-zero = quit
  1848.         call    takclos                 ; close Take file or macro
  1849. squit2: call    isdev                   ; stdin is a device (vs file)?
  1850.         jc      squit3                  ; c = device, not a file
  1851.         mov     flags.extflg,1          ; set Kermit exit flag
  1852. squit3: ret                             ; return failure
  1853. squit4: jmp     rskp                    ; return success, ignore error
  1854.  
  1855. ;
  1856. ; Jumping to this location is like retskp. It assumes the instruction
  1857. ;     after the call is a jmp addr.
  1858.  
  1859. RSKP    PROC    NEAR
  1860.         pop     bp
  1861.         add     bp,3
  1862.         push    bp
  1863.         ret
  1864. RSKP    ENDP
  1865.  
  1866. ; Jumping here is the same as a ret.
  1867.  
  1868. R       PROC    NEAR
  1869.         ret
  1870. R       ENDP
  1871.  
  1872. code    ends
  1873.         end
  1874.